package cn.itsource.ymcc.service.impl;

import cn.itsource.result.PageList;
import cn.itsource.ymcc.doc.CourseDoc;
import cn.itsource.ymcc.dto.Aggs;
import cn.itsource.ymcc.dto.CourseEsSearchDto;
import cn.itsource.ymcc.esmapper.HighlightResultMapper;
import cn.itsource.ymcc.repository.CourseEsRepository;
import cn.itsource.ymcc.service.IEsCourseService;
import cn.itsource.ymcc.utils.EsAggPageList;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.ParsedAggregation;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class EsCourseServiceImpl implements IEsCourseService {
    @Autowired
    private CourseEsRepository courseEsRepository;

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;
    @Autowired
    private HighlightResultMapper highlightResultMapper;

    @Override
    public void saveCourse(CourseDoc doc) {
        courseEsRepository.save(doc);
    }

    @Override
    public void deleteCourse(Long id) {
        courseEsRepository.deleteById(id);
    }

    @Override
    public PageList<CourseDoc> searchCourse(CourseEsSearchDto courseEsSearchDto) {
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();

        // =====================规则====================
        // 创建分页条件
        builder.withPageable(PageRequest.of(courseEsSearchDto.getPage()-1,courseEsSearchDto.getRows()));

        // 创建分页规则
        if(StringUtils.hasLength(courseEsSearchDto.getSortField())){
            String sortName = "";
            // 转换sortFiled
            switch (courseEsSearchDto.getSortField().toLowerCase()){
                case "xl": sortName="saleCount";break;
                case "xp": sortName="onlineTime";break;
                case "pl": sortName="commentCount";break;
                case "jg": sortName="price";break;
                case "rq": sortName="viewCount";break;
            }
            if(StringUtils.hasLength(sortName)){
                SortOrder order = SortOrder.ASC;
                if(StringUtils.hasLength(courseEsSearchDto.getSortType())){
                    order = courseEsSearchDto.getSortType().toUpperCase().equals("DESC")?SortOrder.DESC:SortOrder.ASC;
                }
                builder.withSort(SortBuilders.fieldSort(sortName).order(order));
            }
        }
        // =====================条件====================
        // 建立搜索条件
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        if(StringUtils.hasLength(courseEsSearchDto.getKeyword())){
            // 搜索 keyword，需要分词使用matchQuery
            query.must(QueryBuilders.matchQuery("name",courseEsSearchDto.getKeyword()));
        }

        if(courseEsSearchDto.getCourseTypeId() != null){
            // 搜索课程类型，不需要分词使用termQuery
            query.filter(QueryBuilders.termQuery("courseTypeId",courseEsSearchDto.getCourseTypeId()));
        }
        if(StringUtils.hasLength(courseEsSearchDto.getGradeName())){
            // 搜索课程等级名字
            query.filter(QueryBuilders.termQuery("gradeName",courseEsSearchDto.getGradeName()));
        }
        if(courseEsSearchDto.getPriceMin() != null){
            // 搜索价格最小值
            query.filter(QueryBuilders.rangeQuery("price").gte(courseEsSearchDto.getPriceMin()));
        }
        if(courseEsSearchDto.getPriceMax() != null){
            // 搜索价格最大值
            query.filter(QueryBuilders.rangeQuery("price").lte(courseEsSearchDto.getPriceMax()));
        }

        // 设置高亮
        builder.withHighlightFields(new HighlightBuilder.Field("name")
                .preTags("<font style='color:red'>").postTags("</font>"));

        // ================设置聚合条件===============
        // 等级聚合
        builder.addAggregation(AggregationBuilders.terms("gradeNameAgg").field("gradeName"));
        // 收费规则聚合
        builder.addAggregation(AggregationBuilders.terms("chargeNameAgg").field("chargeName"));

        // 将设置好的的条件放入builder
        builder.withQuery(query);
        NativeSearchQuery build = builder.build();
        // 处理高亮
        AggregatedPage<CourseDoc> page = elasticsearchRestTemplate.queryForPage(build, CourseDoc.class, highlightResultMapper);
        // 接收所有结果集
        Aggregations aggregations = page.getAggregations();
        // 将其格式转化为map
        Map<String, Aggregation> map = aggregations.asMap();

        ParsedStringTerms gradeNameAgg = (ParsedStringTerms) map.get("gradeNameAgg");
        ParsedStringTerms chargeNameAgg = (ParsedStringTerms)map.get("chargeNameAgg");
        Map<String, List<Aggs>> hashMap = new HashMap<>();
        List<? extends Terms.Bucket> buckets = gradeNameAgg.getBuckets();
        List<Aggs> gradeNameAggList = gradeNameAgg.getBuckets().stream()
                .map(bucket -> new Aggs(bucket.getKeyAsString(), bucket.getDocCount()))
                .collect(Collectors.toList());
        List<Aggs> chargeNameAggList = chargeNameAgg.getBuckets().stream()
                .map(bucket -> new Aggs(bucket.getKeyAsString(), bucket.getDocCount()))
                .collect(Collectors.toList());
        hashMap.put("gradeNameAgg",gradeNameAggList);
        hashMap.put("chargeNameAgg",chargeNameAggList);
        // 处理结果返回数据
        return new EsAggPageList(page.getTotalElements(),page.getContent(),hashMap);

    }
}
